package api.betfairAPI;

import api.Market;
import com.google.common.base.Optional;
import com.google.common.collect.Maps;

import java.util.*;

/**
 * User: Darren
 * Date: 28/01/13
 * Time: 1:12 PM
 */
public class BetfairMarket implements Market {
    private int exchangeId;
    private String exchangeName;
    private int marketId;
    private String marketName;
    private String status;
    private Calendar startTime;
    private String country;
    private String currency;
    private String marketStatus;
    private int inPlayDelay;
    private int numberOrWinners;
    private String marketInformation;
    private boolean discountAllowed;
    private String marketBaseRate;
    private long refreshTime;
    private boolean bSPMarket;
    private int numberOfRemovedRunners = 0;
    private ArrayList<RemovedRunner> removedRunners = new ArrayList<RemovedRunner>();
    //  Use a TreeMap because it is sorted according to the natural ordering of its keys
    TreeMap<Integer, Runner> runners = Maps.newTreeMap();

    @Override
    public int getExchangeId() {
        return exchangeId;
    }

    public void setExchangeId(int exchangeId) {
        this.exchangeId = exchangeId;
    }

    @Override
    public String getExchangeName() {
        return exchangeName;
    }
    public void setExchangeName(String exchangeName) {
        this.exchangeName = exchangeName;
    }

    @Override
    public int getMarketId() {
        return marketId;
    }
    public void setMarketId(int marketId) {
        this.marketId = marketId;
    }

    @Override
    public String getMarketName() {
        return marketName;
    }
    public void setMarketName(String marketName) {
        this.marketName = marketName;
    }

    @Override
    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status = status;
    }

    @Override
    public String getStartTime() {
        return startTime.getTime().toString();
    }
    public void setStartTime(Calendar startTime) {
        this.startTime = startTime;
    }

    @Override
    public String getCountry() {
        return country;
    }
    public void setCountry(String country) {
        this.country = country;
    }

    @Override
    public String getCurrency() {
        return currency;
    }
    public void setCurrency(String currency) {
        this.currency = currency;
    }

    public String getMarketStatus() {
        return marketStatus;
    }
    public void setMarketStatus(String marketStatus) {
        this.marketStatus = marketStatus;
    }

    public int getInPlayDelay() {
        return inPlayDelay;
    }
    public void setInPlayDelay(int inPlayDelay) {
        this.inPlayDelay =  inPlayDelay;
    }

    public int getNumberOrWinners() {
        return numberOrWinners;
    }
    public void setNumberOrWinners(int numberOrWinners) {
        this.numberOrWinners = numberOrWinners;
    }

    public String getMarketInformation() {
        return marketInformation;
    }
    public void setMarketInformation(String marketInformation) {
        this.marketInformation = marketInformation;
    }

    public boolean getDiscountAllowed() {
        return discountAllowed;
    }
    public void setDiscountAllowed(boolean discountAllowed) {
        this.discountAllowed = discountAllowed;
    }

    public String getMarketBaseRate() {
        return marketBaseRate;
    }
    public void setMarketBaseRate(String marketBaseRate) {
        this.marketBaseRate = marketBaseRate;
    }

    public long getRefreshTime() {
        return refreshTime;
    }
    public void setRefreshTime(long refreshTime) {
        this.refreshTime = refreshTime;
    }

    public Collection<RemovedRunner> getRemovedRunners() {
        return removedRunners;
    }

    public RemovedRunner getNewRemovedRunner() {
        removedRunners.add(numberOfRemovedRunners, new RemovedRunner());
        ++numberOfRemovedRunners;
        return removedRunners.get(numberOfRemovedRunners - 1);
    }

    public Optional<RemovedRunner> getExistingRemovedRunner(int idx) {
        if (idx < 0 || idx >= removedRunners.size()) {
            return Optional.absent();
        }
        return Optional.of(removedRunners.get(idx));
    }

    public boolean getbSPMarket() {
        return bSPMarket;
    }
    public void setbSPMarket(boolean bSPMarket) {
        this.bSPMarket = bSPMarket;
    }

    @Override
    public Collection<Runner> getRunners() {
        return runners.values();
    }

    public Optional<Runner> getExistingRunner(int selectionId) {
        if (!runners.containsKey(selectionId)) {
            return Optional.absent();
        }
        return Optional.of(runners.get(selectionId));
    }

    public Runner getNewRunner(int selectionId) {
        if (!runners.containsKey(selectionId)) {
            runners.put(selectionId, new Runner());
        }
        return runners.get(selectionId);
    }

    public static class RemovedRunner {
        private String name;
        private Date removedDate;
        private String adjustmentFactor;

        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }

        public Date getRemovedDate() {
            return removedDate;
        }
        public void setRemovedDate(Date removedDate) {
            this.removedDate = removedDate;
        }

        public String getReductionFactor() {
            return adjustmentFactor;
        }
        public void setReductionFactor(String adjustmentFactor) {
            this.adjustmentFactor = adjustmentFactor;
        }
    }

    public static class Runner extends Market.Runner{
        private int selectionId;
        private String name;
        private int orderIndex;
        private double totalAmountMatched;
        private double lastPriceMatched;
        private double handicap;
        private double reductionFactor;
        private boolean vacant;
        private double farSPPrice;
        private double nearSPPrice;
        private double actualSPPrice;
        public static enum PriceType { BACK, LAY }
        private ArrayList<Price> backPrices = new ArrayList<Price>();
        private ArrayList<Price> layPrices = new ArrayList<Price>();

        @Override()
        public int getSelectionId() {
            return selectionId;
        }
        public void setSelectionId(int selectionId) {
            this.selectionId = selectionId;
        }

        @Override
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }

        public int getOrderIndex() {
            return orderIndex;
        }
        public void setOrderIndex(int orderIndex) {
            this.orderIndex = orderIndex;
        }

        @Override
        public double getTotalAmountMatched() {
            return totalAmountMatched;
        }
        public void setTotalAmountMatched(double totalAmountMatched) {
            this.totalAmountMatched = totalAmountMatched;
        }

        @Override
        public double getLastPriceMatched() {
            return lastPriceMatched;
        }
        public void setLastPriceMatched(double lastPriceMatched) {
            this.lastPriceMatched = lastPriceMatched;
        }

        public double getHandicap() {
            return handicap;
        }
        public void setHandicap(double handicap) {
            this.handicap = handicap;
        }

        public double getReductionFactor() {
            return reductionFactor;
        }
        public void setReductionFactor(double reductionFactor) {
            this.reductionFactor = reductionFactor;
        }

        public boolean getVacant() {
            return vacant;
        }
        public void setVacant(boolean vacant) {
            this.vacant = vacant;
        }

        public double getFarSPPrice() {
            return farSPPrice;
        }
        public void setFarSPPrice(double farSPPrice) {
            this.farSPPrice = farSPPrice;
        }

        public double getNearSPPrice() {
            return nearSPPrice;
        }
        public void setNearSPPrice(double nearSPPrice) {
            this.nearSPPrice = nearSPPrice;
        }

        public double getActualSPPrice() {
            return actualSPPrice;
        }
        public void setActualSPPrice(double actualSPPrice) {
            this.actualSPPrice = actualSPPrice;
        }

        @Override
        public Price getBackPrice(int idx) {
            if (idx == backPrices.size()) {
                backPrices.add(idx, new Price());
            }
            while (idx >= backPrices.size()) {
                getBackPrice(backPrices.size());
            }
            return backPrices.get(idx);
        }

        @Override
        public int getBackPricesSize() {
            return backPrices.size();
        }

        @Override
        public Price getLayPrice(int idx) {
            if (idx == layPrices.size()) {
                layPrices.add(idx, new Price());
            }
            while (idx >= layPrices.size()) {
                getLayPrice(layPrices.size());
            }
            return layPrices.get(idx);
        }

        @Override
        public int getLayPricesSize() {
            return layPrices.size();
        }

        public Price getPrice(int idx, PriceType type) {
            if (type == PriceType.BACK) {
                return getBackPrice(idx);
            } else {
                return getLayPrice(idx);
            }
        }
    }

    public static class Price implements Market.Price {
        private double price;
        private double amountAvailable;
        private String type;
        private int depth;

        @Override
        public double getPrice() {
            return price;
        }
        public void setPrice(double price) {
            this.price = price;
        }

        @Override
        public double getAmountAvailable() {
            return amountAvailable;
        }
        public void setAmountAvailable(double amountAvailable) {
            this.amountAvailable = amountAvailable;
        }

        public String getType() {
            return type;
        }
        public void setType(String type) {
            this.type = type;
        }

        public int getDepth() {
            return depth;
        }
        public void setDepth(int depth) {
            this.depth = depth;
        }
    }
}